package com.chenjl.transport.support;

import java.net.InetSocketAddress;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.ExecutionException;

import com.chenjl.Constant;
import com.chenjl.transport.AbstractServer;
import com.chenjl.transport.HookChannelHandler;
import com.chenjl.transport.codec.ObjectDecoder;
import com.chenjl.transport.codec.ObjectEncoder;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
/**
 * 
 * 
 * @author chenjinlong
 */
public class NettyServer extends AbstractServer {
	private EventLoopGroup bossGroup = null;
	private EventLoopGroup workerGroup = null;
	private ServerBootstrap serverBootstrap = null;
	private Channel channel = null;
	private Map<String,Channel> channels = null;
	
	public NettyServer(HookChannelHandler hookChannelHandler) {
		bossGroup = new NioEventLoopGroup();
		workerGroup = new NioEventLoopGroup();
		serverBootstrap = new ServerBootstrap();
		serverBootstrap.group(bossGroup,workerGroup);
		
		serverBootstrap.channel(NioServerSocketChannel.class);
		serverBootstrap.localAddress(new InetSocketAddress(Constant.PORT));
		serverBootstrap.option(ChannelOption.SO_BACKLOG,1024);
		serverBootstrap.handler(new LoggingHandler(LogLevel.INFO));
		
		ServerHandler serverHandler = new ServerHandler(hookChannelHandler);
		channels = serverHandler.getChannels();
		
		//serverBootstrap.childOption(ChannelOption.ALLOCATOR,PooledByteBufAllocator.DEFAULT);
		serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
			@Override
			public void initChannel(SocketChannel socketChannel) throws Exception {
				ChannelPipeline channelPipeline = socketChannel.pipeline();
				
				channelPipeline.addLast(new ObjectEncoder());
                channelPipeline.addLast(new ObjectDecoder());
				channelPipeline.addLast(serverHandler);
			}
		});
	}
	@Override
	public void open() {
		try {
			ChannelFuture channelFuture = serverBootstrap.bind().sync();
			channelFuture.get();
			channel = channelFuture.channel();
			logger.info("server init complete~~");
		}
		catch (InterruptedException e) {
			e.printStackTrace();
		}
		catch (ExecutionException e) {
			e.printStackTrace();
		}
	}
	@Override
	public void close() {
		super.close();
		Collection<Channel> clientChannels = channels.values();
		for(Channel clientChannel : clientChannels) {
			clientChannel.close();
		}
		channels.clear();
		bossGroup.shutdownGracefully();
		workerGroup.shutdownGracefully();
		channel.close();
		close = true;
	}
}